#encoding: utf-8
import tornado.web
import tornado.ioloop
import sys
import time
import os
import simplejson
import logging

import SQLModel
from SQLModel import BLOCK,TRANSACTION,V_IN,V_OUT

class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.db = SQLModel.Session()
        self.peer = self.request.remote_ip
    def hash_from_hash(self, blk_hash):
        #assert len(blk_hash) == 64
        blk_cur = self.db.query(BLOCK).filter(BLOCK.blk_hash == blk_hash)
        if blk_cur.count() == 0:
            logging.info(u'[%s] 未找到block:[%s]'%(self.peer, blk_hash))
            #self.set_status(404)
            #return self.finish({'msg':'Cannot found this block.'})
            self.redirect('/query.html')
        blk_obj = blk_cur.first()
        #return simplejson.dumps( self.retval_from_blk_obj(blk_obj))
        info = self.retval_from_blk_obj(blk_obj)
        trade = self.db.query(TRANSACTION).filter(TRANSACTION.blk_height == blk_obj.blk_height).all()
        trades = []
        for trade_object in trade:
            trades.append(self.retval_from_trade_obj(trade_object))
        trade_count = len(trades)
        self.render('block.html', info=info, trades=trades, trade_count=trade_count)


    def retval_from_blk_obj(self, blk_obj):
        result = {}
        result['height'] = blk_obj.blk_height
        result['hash'] = blk_obj.blk_hash
        result['size'] = blk_obj.blk_size
        result['version'] = blk_obj.blk_version
        result['merkleroot'] = blk_obj.blk_merkleroot
        result['time'] =  time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(blk_obj.blk_time))
        result['nonce'] = blk_obj.blk_nonce
        result['bits'] = blk_obj.blk_bits
        result['difficulty'] = blk_obj.blk_difficulty
        return result

    def retval_from_trade_obj(self, trade_obj):
        result = {}
        result['tx_hash'] = trade_obj.tx_hash
        result['tx_version'] = trade_obj.tx_version
        result['tx_locktime'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(trade_obj.tx_locktime))
        return result



    def hash_from_height(self, height):
        blk_cur = self.db.query(BLOCK).filter(BLOCK.blk_height== height)
        if blk_cur.count == 0:
            logging.info(u'[%s] 未找到指定高度的block:[%s]'%(self.peer, height))
            #return self.finish({'msg':'Cannot found this block.'})
            self.redirect('/query.html')
        #return simplejson.dumps( self.retval_from_blk_obj( blk_cur.first() ))
        blk_obj = blk_cur.first()
        info = self.retval_from_blk_obj(blk_obj)
        trade = self.db.query(TRANSACTION).filter(TRANSACTION.blk_height == blk_obj.blk_height).all()
        trades = []
        for trade_object in trade:
            trades.append(self.retval_from_trade_obj(trade_object))
        trade_count = len(trades)
        self.render('block.html', info=info, trades=trades, trade_count=trade_count)

class AddressHandler(BaseHandler):
    def get(self, address):
        return self.get_tradeinfo_by_address(address)

    def get_tradeinfo_by_address(self, address):
        # 根据address查询tx_hash
        tx_hash = self.db.query(V_OUT.tx_hash).filter(V_OUT.address == address).all()
        if len(tx_hash) == 0:
            logging.info(u'[%s] 该地址没有交易信息:[%s]' % (address, address))
            #return self.finish({'msg': 'No trade info'})
            self.redirect('/query.html')
        else:
            trade = []
            recv_amount = 0
            #print tx_hash
            for item in tx_hash:
                # 根据tx_hash查找交易信息
                # item是一个tuple,只有一个元素，item[0]即为tx_hash
                t_info = self.db.query(TRANSACTION).filter(TRANSACTION.tx_hash == item[0]).first()
                if t_info:
                    amount = self.db.query(V_OUT.amount).filter(V_OUT.tx_hash == item[0]).first()   # 查出来的应为只含一个元素的tuple
                    # TODO: 查询余额
                    trade.append({'tx_hash': t_info.tx_hash,
                               'blk_height': t_info.blk_height,
                               'tx_locktime': t_info.tx_locktime,
                               'currency': 'DKC',
                               'amount': amount[0]})
                    recv_amount += amount[0]
                else:
                    logging.error(u'[%s] 根据该tx_hash查不到交易记录:[%s]' % (item[0], item[0]))
            #return self.finish(simplejson.dumps(result))
            trade_count = len(trade)
            self.render('address.html', trade=trade, trade_count=trade_count, recv_amount=recv_amount)

class GetBlockHashHandler(BaseHandler):
    def get(self, blk_hash):
        return self.finish( self.hash_from_hash(blk_hash) )


class GetBlockFromHeightHandler(BaseHandler):
    def get(self, height):
        try:
            return self.finish( self.hash_from_height(int(height) ) )
        except:
            # 出现异常时表示用户输入了非数字字符
            return self.redirect('/query.html')

class GetTradeByTXHash(BaseHandler):
    def get(self, tx_hash):
        #v_in = self.get_vin_by_txhash(tx_hash)
        #v_out = self.get_vout_by_txhash(tx_hash)
        # TODO:查询trade的时间
        vin = [item for item in self.get_vin_by_txhash(tx_hash)]
        vin_count = len(vin)
        vout = [item for item in self.get_vout_by_txhash(tx_hash)]
        vout_count = len(vout)
        if vin_count == 0 or vout_count == 0:
            self.redirect('/query.html')
        self.render('trade.html', vin=vin, vout=vout, vin_count=vin_count, vout_count=vout_count, time=0, hash=tx_hash)

    def get_vin_by_txhash(self, tx_hash):
        v_in_records = self.db.query(V_IN).filter(V_IN.tx_hash == tx_hash).all()
        for item in v_in_records:
            yield {'raw_msg': item.raw_msg}

    def get_vout_by_txhash(self, tx_hash):
        v_out_records = self.db.query(V_OUT).filter(V_OUT.tx_hash == tx_hash).all()
        for item in v_out_records:
            yield {'amount': item.amount,
                    'address': item.address,
                    'raw_msg': item.raw_msg}

class TemplateHandler(tornado.web.RequestHandler):
    def get(self, template_name):
        self.render(template_name)



def main():
    settings = {
        "template_path" : os.path.join(os.path.dirname(__file__), "templates"),
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
    }

    application = tornado.web.Application([
            (r"/q/address/(\w*)", AddressHandler),
            #(r"/q/getblockhash/(\d)", GetBlockHashHandler),
            (r"/q/getblockbyhash/(\w*)", GetBlockHashHandler),
            (r"/q/getblockbyheight/(\w+)", GetBlockFromHeightHandler),
            (r"/q/gettradebytxhash/(\w+)", GetTradeByTXHash),
            (r"/(.*)", TemplateHandler),
    ], **settings)
    application.listen(sys.argv[1])
    #application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == '__main__':
    main()
